package services

import (
	"cas_central_server/models"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/gorilla/websocket"
	"github.com/imroc/req"
	"github.com/labstack/echo/v4"
)

// listDacsHandler 列出某个设备的DAC
func listDacsHandler(c echo.Context) error {
	deviceName := c.QueryParam("deviceName")
	device, err := models.GetDevice(deviceName)
	if err != nil {
		return err
	}
	type respType struct {
		DACName          string `json:"name"`
		Connected        bool   `json:"connected"`
		Unit             string `json:"unit"`             // 采集卡采集到的数据的单位
		SamplesPerSecond int    `json:"samplesPerSecond"` // 采集卡每秒采集的样本点数目
	}
	results := []respType{}
	for _, dacName := range device.DacNames {
		dac := dacDataMap.get(dacName)
		if dac.Connected {
			results = append(results, respType{
				DACName:          dac.DACName,
				Connected:        true,
				Unit:             dac.Unit,
				SamplesPerSecond: dac.SamplesPerSecond,
			})
		} else {
			results = append(results, respType{
				DACName:   dac.DACName,
				Connected: false,
			})
		}
	}
	return c.JSON(http.StatusOK, results)
}

// pushSampleDataToClientHandler websocket推送数据采集卡的数据到客户端
func pushSampleDataToClientHandler(c echo.Context) error {
	name := c.QueryParam("name")
	if !dacDataMap.exist(name) {
		return forbidden("该采集卡不存在")
	}

	ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil)
	if err != nil {
		return err
	}
	// defer ws.Close()
	// 不主动close websocket，因为后续新的样本点数据到了之后，还要用这个websocket向客户端推送

	pushDataFunc := func(data []sampleData) error {
		bytes, err := json.Marshal(data)
		if err != nil {
			log.Println("convert data to json failed", err)
			return err
		}
		err = ws.WriteMessage(websocket.TextMessage, bytes)
		if err != nil {
			log.Println("failed to write to websocket: ", err)
			return err
		}
		return nil
	}

	pushObserver := &pushToClientObserver{
		dacName:      name,
		currentIndex: 0,
		pushFunc:     pushDataFunc,
	}

	pushObserver.cleanUpFunc = func() {
		dacDataMap.removeObserver(name, pushObserver)
		ws.Close()
	}

	pushObserver.pushRecent()

	dacDataMap.addObserver(name, pushObserver)

	return nil
}

// retrieveDetailedDataHandler 客户端获取某个时间点附近的详细采集卡数据
func retrieveDetailedDataHandler(c echo.Context) error {
	name := c.QueryParam("name")
	if !dacDataMap.exist(name) {
		return forbidden("该采集卡不存在")
	}
	timeUnix, err := strconv.ParseInt(c.QueryParam("timeUnix"), 10, 64)
	if err != nil {
		return badRequest("timeUnix is not an int64 number, error: " + err.Error())
	}
	targetCount, err := strconv.Atoi(c.QueryParam("targetCount"))
	if err != nil {
		return badRequest("targetCount is not a number, error: " + err.Error())
	}

	dac := dacDataMap.get(name)
	addr := fmt.Sprintf("http://%s:%d/savedData", dac.IP, dac.Port)
	resp, err := req.Get(addr, req.QueryParam{
		"timeUnix":    timeUnix,
		"targetCount": targetCount,
	})
	if err != nil {
		c.Logger().Errorf("failed to contact with dac server and get detailed data, error: %v\n", err)
		return err
	}
	bytes, err := resp.ToBytes()
	if err != nil {
		c.Logger().Errorf("failed to read detailed data response body, error: %v\n", err)
		return err
	}
	return c.JSONBlob(http.StatusOK, bytes)
}

// retrieveDetailedDataBeforeHandler 客户端获取某个时间点前的详细采集卡数据
func retrieveDetailedDataBeforeHandler(c echo.Context) error {
	name := c.QueryParam("name")
	if !dacDataMap.exist(name) {
		return forbidden("该采集卡不存在")
	}
	timeUnixNano, err := strconv.ParseInt(c.QueryParam("timeUnixNano"), 10, 64)
	if err != nil {
		return badRequest("timeUnixNano is not an int64 number, error: " + err.Error())
	}
	alreadyGot, err := strconv.Atoi(c.QueryParam("alreadyGot"))
	if err != nil {
		return badRequest("alreadyGot is not a number, error: " + err.Error())
	}
	targetCount, err := strconv.Atoi(c.QueryParam("targetCount"))
	if err != nil {
		return badRequest("targetCount is not a number, error: " + err.Error())
	}

	dac := dacDataMap.get(name)
	addr := fmt.Sprintf("http://%s:%d/savedDataBefore", dac.IP, dac.Port)
	resp, err := req.Get(addr, req.QueryParam{
		"timeUnixNano": timeUnixNano,
		"alreadyGot":   alreadyGot,
		"targetCount":  targetCount,
	})
	if err != nil {
		c.Logger().Errorf("failed to contact with dac server and get detailed data, error: %v\n", err)
		return err
	}
	bytes, err := resp.ToBytes()
	if err != nil {
		c.Logger().Errorf("failed to read detailed data response body, error: %v\n", err)
		return err
	}
	return c.JSONBlob(http.StatusOK, bytes)
}

// retrieveDetailedDataAfterHandler 客户端获取某个时间点后的详细采集卡数据
func retrieveDetailedDataAfterHandler(c echo.Context) error {
	name := c.QueryParam("name")
	if !dacDataMap.exist(name) {
		return forbidden("该采集卡不存在")
	}
	timeUnixNano, err := strconv.ParseInt(c.QueryParam("timeUnixNano"), 10, 64)
	if err != nil {
		return badRequest("timeUnixNano is not an int64 number, error: " + err.Error())
	}
	alreadyGot, err := strconv.Atoi(c.QueryParam("alreadyGot"))
	if err != nil {
		return badRequest("alreadyGot is not a number, error: " + err.Error())
	}
	targetCount, err := strconv.Atoi(c.QueryParam("targetCount"))
	if err != nil {
		return badRequest("targetCount is not a number, error: " + err.Error())
	}

	dac := dacDataMap.get(name)
	addr := fmt.Sprintf("http://%s:%d/savedDataAfter", dac.IP, dac.Port)
	resp, err := req.Get(addr, req.QueryParam{
		"timeUnixNano": timeUnixNano,
		"alreadyGot":   alreadyGot,
		"targetCount":  targetCount,
	})
	if err != nil {
		c.Logger().Errorf("failed to contact with dac server and get detailed data, error: %v\n", err)
		return err
	}
	bytes, err := resp.ToBytes()
	if err != nil {
		c.Logger().Errorf("failed to read detailed data response body, error: %v\n", err)
		return err
	}
	return c.JSONBlob(http.StatusOK, bytes)
}
